package edu.berkeley.nlp.syntax;

import edu.berkeley.nlp.util.IdentityHashSet;
import edu.berkeley.nlp.util.functional.FunctionalUtils;
import edu.berkeley.nlp.util.functional.Predicate;

import java.io.StringReader;
import java.util.List;
import java.util.Set;

/**
 * User: aria42
 * Date: Mar 24, 2009
 */
public enum GrammaticalRole {
  SUBJECT, OBJECT, OTHER, NONE, NULL;

  private static boolean isObject(TreePath<String> treePath) {
    for (TreePath.Transition<String> transition : treePath.getTransitions()) {
      if (transition.getDirection() != TreePath.Direction.UP) {
        return false;
      }
    }
    return true;
  }

  private static boolean isSubject(TreePath<String> treePath) {
    boolean hitS = false;
    for (TreePath.Transition<String> trans : treePath.getTransitions()) {
      Tree<String> toNode = trans.getToNode();
      TreePath.Direction dir = trans.getDirection();
      Tree<String> dest = trans.getToNode();
      if (dest.getLabel().startsWith("S")) {
        hitS = true;
        continue;
      }      
      if (!hitS) {
        if (dir != TreePath.Direction.UP) {
          return false;
        }
      }
      if (hitS) {
        if (!(dir == TreePath.Direction.DOWN_RIGHT)) {
          return false;
        }
      }
    }
    return hitS;
  }

  public static GrammaticalRole findRole(final Tree<String> node, final Tree<String> root)
  {
    Set<Tree<String>> nodes = new IdentityHashSet<Tree<String>>(root.getPostOrderTraversal());
    if (!nodes.contains(node)) {
      return GrammaticalRole.NONE;
    }
    GrammaticalRole curRole = GrammaticalRole.OTHER;
    List<Tree<String>> vpNodes = FunctionalUtils.filter(nodes,new Predicate<Tree<String>>() {
      public Boolean apply(Tree<String> input) {
        return input.isPhrasal() && input.getLabel().startsWith("VP");
      }
    });
    TreePathFinder<String> tpf = new TreePathFinder<String>(root);
    for (Tree<String> vpNode : vpNodes) {
      if (vpNode == node) continue;
      TreePath<String> tp = tpf.findPath(node,vpNode);
      if (isSubject(tp)) {
        return GrammaticalRole.SUBJECT;
      }
      if (isObject(tp)) {
        curRole = GrammaticalRole.OBJECT;
      }
    }
    return curRole;
  }

  public static void main(String[] args) {
    String treeStr = "(ROOT (S (NP (DT The) (NN dog)) (VP (VBD ran) (NN home))))";
    StringReader reader = new StringReader(treeStr);
    Tree<String> tree = new Trees.PennTreeReader(reader).next();
    Tree<String> subjNode = tree.getChildren().get(0).getChildren().get(0);
    Tree<String> objNode = tree.getChild(0).getChild(1).getChild(1);
    System.out.println("subjNode is " + GrammaticalRole.findRole(subjNode,tree));
    System.out.println("objNode is " + GrammaticalRole.findRole(objNode,tree));
  }
}
